package org.xbl.xchain.sdk.block;

import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.apache.commons.codec.digest.DigestUtils;
import org.xbl.xchain.sdk.amino.Codec;
import org.xbl.xchain.sdk.tx.StdTx;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Data
public class BlockInfo {

    @JSONField(name = "block_id")
    private BlockId blockId;

    private Block block;


    @Data
    public static class Block {
        private BlockHeader header;

        private TxData data;

        private Object evidence;

        @JSONField(name = "last_commit")
        private Commit lastCommit;
    }

    @Data
    public static class TxData {
        private List<String> txs;
    }

    @Data
    public static class BlockId {
        private String hash;
        private Parts parts;
    }

    @Data
    public static class Parts {
        private String total;
        private String hash;
    }

    @Data
    public static class Version {
        private String app;
        private String block;
    }


    @Data
    public static class BlockHeader {
        @JSONField(name = "chain_id")
        private String chainId;
        @JSONField(name = "validators_hash")
        private String validatorsHash;
        @JSONField(name = "consensus_hash")
        private String consensusHash;
        @JSONField(name = "proposer_address")
        private String proposerAddress;
        @JSONField(name = "next_validators_hash")
        private String nextValidatorsHash;
        private Version version;
        @JSONField(name = "data_hash")
        private String dataHash;
        @JSONField(name = "last_results_hash")
        private String lastResultsHash;
        @JSONField(name = "last_block_id")
        private BlockId lastBlockId;
        @JSONField(name = "evidence_hash")
        private String evidenceHash;
        @JSONField(name = "app_hash")
        private String appHash;
        private String time;
        private String height;
        @JSONField(name = "last_commit_hash")
        private String lastCommitHash;
    }

    @Data
    public static class Commit {
        private String height;
        private String round;
        @JSONField(name = "block_id")
        private BlockId blockId;
        private List<Signature> signatures;
    }

    @Data
    public static class Signature {
        private String signature;
        @JSONField(name = "validator_address")
        private String validatorAddress;
        @JSONField(name = "block_id_flag")
        private Integer blockIdFlag;
        private String timestamp;
    }

    @JSONField(serialize = false)
    public Long getBlockHeight() {
        return this.block != null ? Long.valueOf(this.block.getHeader().getHeight()) : null;
    }

    @JSONField(serialize = false)
    public String getBlockHash() {
        return this.blockId != null ? this.blockId.getHash() : null;
    }

    @JSONField(serialize = false)
    public String getLastBlockHash() {
        return this.block != null ? this.block.getLastCommit().getBlockId().getHash() : null;
    }

    @JSONField(serialize = false)
    public String getDataHash() {
        return this.block != null ? this.block.getHeader().getDataHash() : null;
    }

    //13位时间戳
    @JSONField(serialize = false)
    public Date getBlockTime() throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.CHINESE);
        format.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date date = format.parse(this.block.getHeader().getTime().substring(0, 19) + "Z");
        return date;
    }

    @JSONField(serialize = false)
    public List<StdTxInfo> getTxs() {
        return getTxs(org.xbl.xchain.sdk.types.Version.NONCE);
    }

    @JSONField(serialize = false)
    public List<StdTxInfo> getTxs(String version) {
        List<StdTxInfo> stdTxInfos = new ArrayList<>();
        TxData txData = this.getBlock().getData();
        if (txData != null && txData.getTxs() != null && txData.getTxs().size() > 0) {
            for (String tx : txData.getTxs()) {
                byte[] txBytes = Base64.getDecoder().decode(tx.getBytes());
                String txHash = DigestUtils.sha256Hex(txBytes).toUpperCase();
                StdTx stdTx = Codec.getAmino(version).unmarshalBinaryLengthPrefixed(txBytes, StdTx.class);
                StdTxInfo stdTxInfo = new StdTxInfo(stdTx.getMsg(), stdTx.getFee(), stdTx.getSignatures(), stdTx.getMemo(), stdTx.getNonce(), txHash);
                stdTxInfos.add(stdTxInfo);
            }
        }
        return stdTxInfos;
    }
}
